package top.lshaci.learning.springboot.jpaquerydsl.core;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * DslMatcherUtil
 *
 * @author liangxu
 */
public class DslMatcherUtil {

    /**
     * 日期 匹配方式映射缓存
     */
    private static final Map<DslMatcher, DslConditionMatcher> dateMapping = new HashMap<>();

    /**
     * 时间 匹配方式映射缓存
     */
    private static final Map<DslMatcher, DslConditionMatcher> timeMapping = new HashMap<>();

    /**
     * 日期时间 匹配方式映射缓存
     */
    private static final Map<DslMatcher, DslConditionMatcher> dateTimeMapping = new HashMap<>();

    /**
     * 字符串 匹配方式映射缓存
     */
    private static final Map<DslMatcher, DslConditionMatcher> stringMapping = new HashMap<>();

    /**
     * 数字 匹配方式映射缓存
     */
    private static final Map<DslMatcher, DslConditionMatcher> numberMapping = new HashMap<>();

    /**
     * 根据字段和查询注解，获取具体的条件匹配方式
     *
     * @param field        字段
     * @param dslCondition 查询注解
     * @return 条件匹配方式
     */
    public static DslConditionMatcher handle(Field field, DslCondition dslCondition) {
        return handle(field, dslCondition == null ? DslMatcher.EQ : dslCondition.matcher());
    }

    /**
     * 根据字段和匹配方式，获取具体的条件匹配方式
     *
     * @param field   字段
     * @param matcher 匹配方式
     * @return 条件匹配方式
     */
    public static DslConditionMatcher handle(Field field, DslMatcher matcher) {
        Class<?> type = field.getType();

        if (Iterable.class.isAssignableFrom(type)) {
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType) {
                type = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
            }
        }

        if (type.isArray()) {
            type = type.getComponentType();
        }

        if (Number.class.isAssignableFrom(type)) {
            return numberMapping.get(matcher);
        }
        if (type == String.class) {
            return stringMapping.get(matcher);
        }
        if (type == LocalDate.class) {
            return dateMapping.get(matcher);
        }
        if (type == LocalTime.class) {
            return timeMapping.get(matcher);
        }
        if (type == Date.class || type == LocalDateTime.class || type == Instant.class) {
            return dateTimeMapping.get(matcher);
        }

        return null;
    }

    // 初始化匹配方式映射
    static {
        // 字符串匹配方式
        stringMapping.put(DslMatcher.EQ, DslConditionMatcher.String_EQ);
        stringMapping.put(DslMatcher.LT, DslConditionMatcher.String_LT);
        stringMapping.put(DslMatcher.LE, DslConditionMatcher.String_LE);
        stringMapping.put(DslMatcher.GT, DslConditionMatcher.String_GT);
        stringMapping.put(DslMatcher.GE, DslConditionMatcher.String_GE);
        stringMapping.put(DslMatcher.IN, DslConditionMatcher.String_IN);
        stringMapping.put(DslMatcher.LK, DslConditionMatcher.String_LK);
        stringMapping.put(DslMatcher.SW, DslConditionMatcher.String_SW);
        stringMapping.put(DslMatcher.EW, DslConditionMatcher.String_EW);
        stringMapping.put(DslMatcher.BLK, DslConditionMatcher.String_BLK);
        stringMapping.put(DslMatcher.BSW, DslConditionMatcher.String_BSW);
        stringMapping.put(DslMatcher.BEW, DslConditionMatcher.String_BEW);
        stringMapping.put(DslMatcher.NOT_IN, DslConditionMatcher.String_NOT_IN);
        // 数字匹配方式
        numberMapping.put(DslMatcher.EQ, DslConditionMatcher.Number_EQ);
        numberMapping.put(DslMatcher.LT, DslConditionMatcher.Number_LT);
        numberMapping.put(DslMatcher.LE, DslConditionMatcher.Number_LE);
        numberMapping.put(DslMatcher.GT, DslConditionMatcher.Number_GT);
        numberMapping.put(DslMatcher.GE, DslConditionMatcher.Number_GE);
        numberMapping.put(DslMatcher.IN, DslConditionMatcher.Number_IN);
        numberMapping.put(DslMatcher.NOT_IN, DslConditionMatcher.Number_NOT_IN);
        // 日期匹配方式
        dateMapping.put(DslMatcher.EQ, DslConditionMatcher.Date_EQ);
        dateMapping.put(DslMatcher.LT, DslConditionMatcher.Date_LT);
        dateMapping.put(DslMatcher.LE, DslConditionMatcher.Date_LE);
        dateMapping.put(DslMatcher.GT, DslConditionMatcher.Date_GT);
        dateMapping.put(DslMatcher.GE, DslConditionMatcher.Date_GE);
        // 时间匹配方式
        timeMapping.put(DslMatcher.EQ, DslConditionMatcher.Time_EQ);
        timeMapping.put(DslMatcher.LT, DslConditionMatcher.Time_LT);
        timeMapping.put(DslMatcher.LE, DslConditionMatcher.Time_LE);
        timeMapping.put(DslMatcher.GT, DslConditionMatcher.Time_GT);
        timeMapping.put(DslMatcher.GE, DslConditionMatcher.Time_GE);
        // 时间日期匹配方式
        dateTimeMapping.put(DslMatcher.EQ, DslConditionMatcher.DateTime_EQ);
        dateTimeMapping.put(DslMatcher.LT, DslConditionMatcher.DateTime_LT);
        dateTimeMapping.put(DslMatcher.LE, DslConditionMatcher.DateTime_LE);
        dateTimeMapping.put(DslMatcher.GT, DslConditionMatcher.DateTime_GT);
        dateTimeMapping.put(DslMatcher.GE, DslConditionMatcher.DateTime_GE);
    }
}
